package com.maduar.mybatis.demo.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * Description: 
 * 
 * @author danny.pang danny.pang@ebizprise.com
 * @date 2019-11-06 14:23
 * 
 */
@Configuration
public class RedisConfig {

    public static Logger logger = LoggerFactory.getLogger(RedisConfig.class);

    private final int DB_INDEX = 0;

    @Value("$" + "{redis.host:localhost}")
    private String host;

    @Value("$" + "{redis.port:6379}")
    private int port;

    @Value("$" + "{redis.database:0}")
    private int database;

    @Value("$" + "{redis.password:}")
    private String password;

    @Value("$" + "{redis.pool.max-active:8}")
    private int maxActive;

    @Value("$" + "{redis.pool.max-wait:1000}")
    private int maxWait;

    @Value("$" + "{redis.pool.max-idle:8}")
    private int maxIdle;

    @Value("$" + "{redis.pool.min-idle:0}")
    private int minIdle;

    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        RedisStandaloneConfiguration redisConfig = new RedisStandaloneConfiguration();
        redisConfig.setHostName(host);
        redisConfig.setPort(port);
        redisConfig.setDatabase(database);
        redisConfig.setPassword(password);
        redisConfig.setDatabase(DB_INDEX);

        GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
        // 连接池中最大连接数
        poolConfig.setMaxTotal(maxActive);
        // 调用者最大阻塞时间, -1 永不超时
        poolConfig.setMaxWaitMillis(maxWait);
        // 最大空闲连接数
        poolConfig.setMaxIdle(maxIdle);
        // 最小空闲连接数
        poolConfig.setMinIdle(minIdle);

        JedisClientConfiguration jedisClientConfiguration =
                JedisClientConfiguration.builder().usePooling().poolConfig(poolConfig).build();

        return new JedisConnectionFactory(redisConfig, jedisClientConfiguration);
    }

    @Bean
    public RedisTemplate<String, Object> redisTemplate(@Qualifier("redisConnectionFactory") RedisConnectionFactory factory) {

        RedisTemplate<String, Object> template = new RedisTemplate<>();
        // 配置连接工厂
        template.setConnectionFactory(factory);

        //使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值（默认使用JDK的序列化方式）
        Jackson2JsonRedisSerializer jacksonSeial = new Jackson2JsonRedisSerializer(Object.class);

        ObjectMapper om = new ObjectMapper();
        // 指定要序列化的域，field,get和set,以及修饰符范围，ANY是都有包括private和public
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 指定序列化输入的类型，类必须是非final修饰的，final修饰的类，比如String,Integer等会跑出异常
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jacksonSeial.setObjectMapper(om);

        // 值采用json序列化
        template.setValueSerializer(jacksonSeial);
        //使用StringRedisSerializer来序列化和反序列化redis的key值
        template.setKeySerializer(new StringRedisSerializer());

        // 设置hash key 和value序列化模式
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(jacksonSeial);
        template.afterPropertiesSet();

        logger.info("start redis ...");
        return template;
    }
}